package com.youlu.campus.service.visitor.impl;

import com.alibaba.fastjson.JSON;
import com.mongodb.client.result.DeleteResult;
import com.youlu.campus.base.exception.BusinessException;
import com.youlu.campus.common.utils.ExcelUtil;

import com.youlu.campus.common.utils.RedisKeyUtil;
import com.youlu.campus.entity.OrderInfo;
import com.youlu.campus.entity.UserBlackList;
import com.youlu.campus.entity.UserPO;
import com.youlu.campus.entity.UserParticipateActivityInfo;
import com.youlu.campus.entity.VO.req.UserBlackListQueryVO;
import com.youlu.campus.entity.WechatH5UserPO;
import com.youlu.campus.entity.data.BlackListImport;
import com.youlu.campus.service.order.OrderService;
import com.youlu.campus.service.visitor.UserBlackListService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayInputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;


@Slf4j
@Service
public class UserBlackListServiceImpl implements UserBlackListService {
    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private OrderService orderService;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    @Override
    public boolean exist(String userId) {
        String key = RedisKeyUtil.getUserBlackListKey(userId);
        String s = redisTemplate.opsForValue().get(key);
        if ("true".equals(s)) {
            log.info("exist 用户在黑名单中 userId:{}", userId);
            return true;
        }
        Query query = new Query().addCriteria(Criteria.where("userId").is(userId).and("status").is(Boolean.TRUE));
        UserBlackList userBlackList = mongoTemplate.findOne(query, UserBlackList.class);
        if (Objects.isNull(userBlackList)) {
            redisTemplate.opsForValue().set(key, "false", 30, TimeUnit.MINUTES);
            return false;
        }
        redisTemplate.opsForValue().set(key, "true", 30, TimeUnit.MINUTES);
        log.info("exist 用户在黑名单中 userId:{}", userId);
        return true;
    }

    @Override
    public boolean create(UserBlackList req) {
        if (Objects.isNull(req) || (StringUtils.isBlank(req.getMobile()) && StringUtils.isBlank(req.getUserId()))) {
            log.error(":>>> 创建用户黑名单错误:参数错误");
            return false;
        }
        Date date = new Date();
        if (StringUtils.isNotBlank(req.getMobile())) {
            Query query1 = new Query().addCriteria(Criteria.where("mobile").is(req.getMobile()));
            List<UserPO> userPOS = mongoTemplate.find(query1, UserPO.class);
            if (!CollectionUtils.isEmpty(userPOS)) {
                for (UserPO userPO : userPOS) {
                    UserBlackList insert = new UserBlackList();
                    req.setCreatedTime(date);
                    req.setId(null);
                    BeanUtils.copyProperties(req, insert);
                    insert.setUserId(userPO.getId());
                    insert.setOptTime(date);
                    this.setNickName(insert, userPO.getId());
                    this.setUniversityInfo(insert, userPO.getId());
                    insert.setStatus(true);
                    mongoTemplate.insert(insert);
                    log.info(":>>> 插入黑名单:{},userId:{}", req.getMobile(), userPO.getId());
                }
            }
        } else if (StringUtils.isNotBlank(req.getUserId())) {
            this.setNickName(req, req.getUserId());
            this.setUniversityInfo(req, req.getUserId());
            req.setCreatedTime(date);
            req.setOptTime(date);
            req.setId(null);
            req.setStatus(true);
            mongoTemplate.insert(req);
            log.info(":>>> 插入黑名单:{},userId:{}", req.getMobile(), req.getUserId());
        }
        deleteCache(req.getUserId());
        return true;
    }

    @Override
    public Page<UserBlackList> list(UserBlackListQueryVO req) {
        log.info(":>>> 开始用户黑名单列表:{}", JSON.toJSONString(req));
        if (Objects.isNull(req)) {
            log.error(":>>> 获取用户黑名单参数错误");
            throw new BusinessException("获取用户黑名单参数错误");
        }
        Query query = new Query();
        query.addCriteria(Criteria.where("deleted").ne(Boolean.TRUE));
        if (StringUtils.isNotBlank(req.getMobile())) {
            query.addCriteria(Criteria.where("mobile").is(req.getMobile()));
        }
        if (StringUtils.isNotBlank(req.getName())) {
            query.addCriteria(Criteria.where("name").is(req.getName()));
        }
        if (StringUtils.isNotBlank(req.getUniversityId())) {
            query.addCriteria(Criteria.where("universityId").is(req.getUniversityId()));
        }
        if (StringUtils.isNotBlank(req.getType())) {
            query.addCriteria(Criteria.where("type").is(req.getType()));
        }
        if (StringUtils.isNotBlank(req.getLimitType())) {
            query.addCriteria(Criteria.where("limitType").is(req.getLimitType()));
        }
        if (Objects.nonNull(req.getStatus())) {
            query.addCriteria(Criteria.where("status").is(req.getStatus()));
        }
        if (StringUtils.isNotBlank(req.getActivityId())) {
            query.addCriteria(Criteria.where("activityIds").is(req.getActivityId()));
        }
        if (StringUtils.isNotBlank(req.getUserId())) {
            query.addCriteria(Criteria.where("userId").is(req.getUserId()));
        }
        Long count = mongoTemplate.count(query, UserBlackList.class);
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "createdTime"));
        Sort sort = Sort.by(Sort.Direction.DESC, "createdTime");
        query.with(sort);
        List<UserBlackList> signUpUserList = mongoTemplate.find(query.with(pageRequest), UserBlackList.class);
        return PageableExecutionUtils.getPage(signUpUserList, pageRequest, () -> count);
    }

    @Override
    public boolean update(UserBlackList req) {
        if (Objects.isNull(req) || StringUtils.isBlank(req.getId())) {
            log.error(":>>> 修改黑名单参数错误");
            return false;
        }
        UserBlackList userBlack = mongoTemplate.findById(req.getId(), UserBlackList.class);
        if (Objects.isNull(userBlack)) {
            return false;
        }
        boolean up = false;
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getId()));
        Update update = new Update();
        if (StringUtils.isNotBlank(req.getName())) {
            update.set("name", req.getName());
            up = true;
        }
        if (StringUtils.isNotBlank(req.getDesc())) {
            update.set("desc", req.getDesc());
            up = true;
        }
        if (StringUtils.isNotBlank(req.getUniversityId())) {
            update.set("desc", req.getUniversityId());
            up = true;
        }
        if (Objects.nonNull(req.getStatus())) {
            update.set("status", req.getStatus());
            up = true;
        }
        if (StringUtils.isNotBlank(req.getType())) {
            update.set("type", req.getType());
            up = true;
        }
        if (StringUtils.isNotBlank(req.getLimitType())) {
            update.set("limitType", req.getLimitType());
            up = true;
        }
        if (StringUtils.isNotBlank(req.getComments())) {
            update.set("comments", req.getComments());
            up = true;
        }
        if (!CollectionUtils.isEmpty(req.getActivityIds())) {
            update.set("activityIds", req.getActivityIds());
            up = true;
        }

        if (up) {
            boolean b = mongoTemplate.updateFirst(query, update, UserBlackList.class).getModifiedCount() > 0 ? true : false;
            //删除缓存
            deleteCache(userBlack.getUserId());
            return b;
        }
        return false;
    }

    @Override
    public boolean delete(String id) {
        UserBlackList userBlack = mongoTemplate.findById(id, UserBlackList.class);
        if (Objects.isNull(userBlack)) {
            return true;
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        DeleteResult deleteResult = mongoTemplate.remove(query, UserBlackList.class);
        //删除缓存
        deleteCache(userBlack.getUserId());
        return deleteResult.getDeletedCount() > 0 ? true : false;
    }

    @Override
    public UserBlackList findOne(String id) {
        Query query = new Query().addCriteria(Criteria.where("id").is(id));
        return mongoTemplate.findOne(query, UserBlackList.class);
    }

    @Override
    public boolean create(String optUser, byte[] inputStream, String fileName, String comments) {
        if (Objects.isNull(comments) || Objects.isNull(inputStream) || StringUtils.isBlank(fileName)) {
            log.error(":>>> 批量创建黑名单参数错误");
            throw new BusinessException("创建黑名单参数错误");
        }
        Date date = new Date();
        try {
            List<BlackListImport> models = ExcelUtil.readData(new ByteArrayInputStream(inputStream), BlackListImport.class);
            if (CollectionUtils.isEmpty(models)) {
                return true;
            }
            for (BlackListImport blackListImport : models) {
                singleBatch(blackListImport, optUser, fileName, comments, date);
            }
        } catch (Exception e) {
            log.error(":>>> 批量创建黑名单错误:{}", e);
            return false;
        }
        return true;
    }

    @Override
    public Boolean existsByMobile(String mobile) {
        if (StringUtils.isBlank(mobile)) {
            return Boolean.FALSE;
        }
        Query query = new Query().addCriteria(Criteria.where("mobile").is(mobile).and("status").is(Boolean.TRUE));
        return mongoTemplate.exists(query, UserBlackList.class);
    }

    private void singleBatch(BlackListImport blackListImport, String optUser, String fileName, String comments, Date date) {
        if (Objects.isNull(blackListImport) ||
                StringUtils.isBlank(blackListImport.getBizData()) || StringUtils.isBlank(blackListImport.getType())
                || StringUtils.isBlank(blackListImport.getLimitType())) {
            log.error(":>>> 业务数据异常:{}", JSON.toJSONString(blackListImport));
            return;
        }
        UserBlackList req = new UserBlackList();
        //限制类型,1:单次活动,2:所有活动
        switch (blackListImport.getLimitType()) {
            case "1":
                if (StringUtils.isBlank(blackListImport.getActivityIds()) || !blackListImport.getActivityIds().contains(",")) {
                    log.error(":>>> 限制单词活动,活动ID为空,或活动ID不以英文逗号分割");
                    return;
                }
                String[] array = blackListImport.getActivityIds().split(",");
                List<String> aIds = new ArrayList<>();
                for (int i = 0; i < array.length; i++) {
                    aIds.add(array[i]);
                }
                req.setActivityIds(aIds);
                break;
            case "2":
                break;
            default:
                break;
        }
        if (Boolean.TRUE.equals(blackListImport.getComplainted())) {
            if (!blackListImport.getBizData().startsWith("20")) {
                log.error(":>>. 投诉数据订单应该以20开头");
                return;
            }
            OrderInfo orderInfo = orderService.findByOrderNo(blackListImport.getBizData());
            if (Objects.isNull(orderInfo)) {
                log.error(":>>> 订单:{} 不存在", blackListImport.getBizData());
                return;
            }
            req.setMobile(orderInfo.getMobile());
            req.setUserId(orderInfo.getAccountInfoId());
            req.setOptUser(optUser);
            req.setStatus(Boolean.TRUE);
            req.setOptTime(date);
            req.setCreatedTime(date);
            req.setComments(comments);
            req.setLimitType(blackListImport.getLimitType());
            req.setOptWay("2");
            req.setFileName(fileName);
            req.setBatchId(fileName + "-" + date.getTime());
        } else {
            if (!blackListImport.getBizData().startsWith("1") && !(blackListImport.getBizData().length() == 11)) {
                log.error(":>>. 非投诉数据订单应该以1开头,并且长度为11位");
                return;
            }
            req.setMobile(blackListImport.getBizData());
            req.setOptUser(optUser);
            req.setStatus(Boolean.TRUE);
            req.setOptTime(date);
            req.setCreatedTime(date);
            req.setComments(comments);
            req.setLimitType(blackListImport.getLimitType());
            req.setOptWay("2");
            req.setFileName(fileName);
            req.setBatchId(fileName + "-" + date.getTime());
        }

        create(req);
    }

    private void setNickName(UserBlackList req, String userId) {
        Query queryDetail = new Query().addCriteria(Criteria.where("accountInfoId").is(userId));
        WechatH5UserPO wechatH5UserPO = mongoTemplate.findOne(queryDetail, WechatH5UserPO.class);
        if (Objects.nonNull(wechatH5UserPO)) {
            req.setNickName(wechatH5UserPO.getNickName());
            req.setAvatarUrl(wechatH5UserPO.getAvatarUrl());
            req.setUniversityId(wechatH5UserPO.getUniversityId());
        }
    }

    private void setUniversityInfo(UserBlackList req, String userId) {
        Query query = new Query().addCriteria(Criteria.where("userId").is(userId).and("joined").is(Boolean.TRUE));
        UserParticipateActivityInfo up = mongoTemplate.findOne(query, UserParticipateActivityInfo.class);
        if (Objects.nonNull(up)) {
            req.setUniversityId(up.getUniversityId());
            req.setUniversityName(up.getUniversityName());
        }
    }

    private void deleteCache(String userId) {
        if (StringUtils.isBlank(userId)) {
            return;
        }
        String key = RedisKeyUtil.getUserBlackListKey(userId);
        redisTemplate.delete(key);
    }
}
